package com.x.service;

import com.x.dao.StudentDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;

/**
 * ClassName: StudentService
 * Package: IntelliJ IDEA
 * Description:
 * 事务注解的使用
 *
 * Written by HanXu
 * Create 2024.09.05 21:27
 */

@Service
public class StudentService {

    @Autowired
    private StudentDao studentDao;


    /**
     * 开启事务功能:
     *      @Transactional
     *      位置: 类(类内所有方法都有事务)、方法(该方法支持事务)
     *      方法上的注解会覆盖类上的统一注解！
     *
     *      只读模式：@Transactional(readOnly = true)
     *          在该模式不能执行修改语句
     *
     *      一般情况下，@Transactional是添加到类上，类中的查询方法可以设置@Transactional(readOnly = true)
     *
     *  事务隔离级别设置:
     *      Isolation.DEFAULT
     *      Isolation.READ_COMMITTED (推荐)
     *      Isolation.READ_UNCOMMITTED
     *      REPEATABLE_READ
     */
    @Transactional(isolation = Isolation.DEFAULT)
    public void changeInfo(){
        studentDao.updateAgeById(99,9);
        studentDao.updateNameById("Jacky",9);
    }


    @Transactional
    public void changeInfo1(){
        studentDao.updateAgeById(99,9);
        int i = 1/0; //发生异常，事务回滚
        studentDao.updateNameById("Jacky",9);
    }


    //事务超时设置为3秒
    //方法内部线程休眠4秒，事务回滚
    //异常:TransactionTimedOutException
    @Transactional(readOnly = false, timeout = 3)
    public void changeInfo2(){
        studentDao.updateAgeById(99,9);
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        studentDao.updateNameById("Jacky",9);
    }

    @Transactional
    public void changeInfo3() throws FileNotFoundException {
        studentDao.updateAgeById(99,9); //这样第一条会修改成功
        new FileOutputStream("xxx");
        studentDao.updateNameById("Jacky",9);//但是第二条不会成功
    }


    //配置rollbackFor = Exception.class, 整体回滚
    @Transactional(rollbackFor = Exception.class) //指定Exception回滚
    public void changeInfo4() throws FileNotFoundException {
        studentDao.updateAgeById(99,9);
        new FileOutputStream("xxx");
        studentDao.updateNameById("Jacky",9);
    }


    //查询操作可以放只读事务，但是查询操作没必要使用只读事务
    @Transactional(readOnly = true)
    public String getName(){
        return null;
    }

    /**
     * 事务的传播行为
     *      Propagation.REQUIRED:
     *          如果父方法有事务就加入(不独立,与父方法为同一事务), 父方法没有事务就新建(独立)
     *
     *
     *      Propagation.REQUIRES_NEW:
     *          不管父方法是否有事务，子方法的事务都是独立的
     *
     *
     *      下面的设置, changeAge()报错不会影响changeName()的执行，因为不是同一事务
     *      若changeName()也设置成Propagation.REQUIRED,则两方法同时回滚
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void changeName(){
        studentDao.updateNameById("小狗", 9);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void changeAge(){
        studentDao.updateAgeById(900, 9);
        int i = 1/0;
    }
}
